/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.nodes; import java.awt.datatransfer.*; import java.awt.dnd.DnDConstants; import java.io.IOException; import java.io.Serializable; import java.text.MessageFormat; import org.openide.util.NbBundle; import org.openide.util.datatransfer.*; /** Class that contains specific datatransfer flavors and methods to work with * nodes. There are flavors to allow a node * to be copied or cut, and to decide its paste types. * <p>This is a dummy utility class--no instances are possible. * * @author Jaroslav Tulach */ public abstract class NodeTransfer extends Object { private NodeTransfer() {} /** Constants for drag-n-drop operations. * Are exactly the same as constants * in {@link DnDConstants}. */ public static final int DND_NONE = DnDConstants.ACTION_NONE; public static final int DND_COPY = DnDConstants.ACTION_COPY; public static final int DND_MOVE = DnDConstants.ACTION_MOVE; public static final int DND_COPY_OR_MOVE = DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE; public static final int DND_LINK = DnDConstants.ACTION_LINK; public static final int DND_REFERENCE = DnDConstants.ACTION_LINK; /** Constant indicating copying to the clipboard. * Equal to {@link #DND_COPY}, because * copy to clipboard and d'n'd copy should be the same. */ public static final int CLIPBOARD_COPY = DND_COPY; /** Constant indicating cutting to the clipboard. */ public static final int CLIPBOARD_CUT = 0x04; /** Generic mask for copying nodes (do not destroy the original). * Equal to {@link #CLIPBOARD_COPY} or {@link #DND_COPY}. */ public static final int COPY = CLIPBOARD_COPY | DND_COPY; /** Generic mask for moving nodes (destroy the original). * Equal to {@link #CLIPBOARD_CUT} or {@link #DND_MOVE}. */ public static final int MOVE = CLIPBOARD_CUT | DND_MOVE; /** Flavor for representation class {@link NodeTransfer.Paste}. * Provides methods for obtaining a set of {@link PasteType}s when * the target node is known. */ private static final DataFlavor nodePasteFlavor = new DataFlavor ( "application/x-java-openide-nodepaste;class=java.io.InputStream", // NOI18N Node.getString ("LBL_nodePasteFlavor") ); /** message format to create and parse the mimetype */ private static MessageFormat dndMimeType = new MessageFormat ( "application/x-java-openide-nodednd;class=java.io.InputStream;mask={0}" // NOI18N ); /** Creates data flavor for given mask of dnd actions. * @param actions any mask of dnd constants DND_* and CLIPBOARD_* */ private static DataFlavor createDndFlavor (int actions) { try { return new DataFlavor (dndMimeType.format (new Object[] { new Integer (actions) })); } catch (ClassNotFoundException ex) { throw new InternalError (); } } /** Creates transferable that represents a node operation, such as cut-to-clipboard. * The transferable will be recognizable by {@link #node}, {@link #nodes}, and {@link #cookie}. * * @param n the node to create a transferable for * @param actions the action performed on the node * @return the transferable */ public static ExTransferable.Single transferable (final Node n, int actions) { return new ExTransferable.Single (createDndFlavor (actions)) { public Object getData () { return n; } }; } /** Obtain a node from a transferable. * Probes the transferable in case it includes a flavor corresponding * to a node operation (which you must specify a mask for). * * @param t transferable * @param action one of the <code>DND_*</code> or <code>CLIPBOARD_*</code> constants * @return the node or <code>null</code> */ public static Node node (Transferable t, int action) { DataFlavor[] flavors = t.getTransferDataFlavors (); if (flavors == null) { return null; } int len = flavors.length; String subtype = "x-java-openide-nodednd"; // NOI18N String primary = "application"; // NOI18N String mask = "mask"; // NOI18N for (int i = 0; i < len; i++) { DataFlavor df = flavors[i]; if ( df.getSubType ().equals (subtype) && df.getPrimaryType ().equals (primary) ) { try { int m = Integer.valueOf (df.getParameter (mask)).intValue (); if ((m & action) != 0) { // found the node return (Node)t.getTransferData (df); } } catch (NumberFormatException nfe) { maybeReportException (nfe); } catch (ClassCastException cce) { maybeReportException (cce); } catch (IOException ioe) { maybeReportException (ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException (ufe); } } } return null; } /** Obtain a list of nodes from a transferable. * If there is only a single node in the transferable, this will just return a singleton * array like {@link #node}. * If there is a {@link ExTransferable#multiFlavor multiple transfer} (of at least one element), * each element of which * contains a node, then an array of these will be returned. * If neither of these things is true, <code>null</code> will be returned. * <p>This is a convenience method intended for those who wish to specially support pastes * of multiple nodes at once. (By default, {@link org.openide.explorer.ExplorerActions} will * fallback to presenting each component of a multiple-item transferable separately when checking for paste * types on a target node, so if you have only one paste type and it makes no difference whether all of the nodes * are pasted together or separately, you can just use {@link #node}.) * <p>If you wish to test for cookies, you should do so manually * according to your specific logic. * @param t the transferable to probe * @param action a DnD or clipboard constant * @return a non-empty array of nodes, or <code>null</code> */ public static Node[] nodes (Transferable t, int action) { try { if (t.isDataFlavorSupported (ExTransferable.multiFlavor)) { MultiTransferObject mto = (MultiTransferObject) t.getTransferData (ExTransferable.multiFlavor); int count = mto.getCount (); Node[] ns = new Node[count]; boolean ok = true; for (int i = 0; i < count; i++) { Node n = node (mto.getTransferableAt (i), action); if (n == null) { ok = false; break; } else { ns[i] = n; } } if (ok && count > 0) return ns; } else { Node n = node (t, action); if (n != null) return new Node[] { n }; } } catch (ClassCastException cce) { maybeReportException (cce); } catch (IOException ioe) { maybeReportException (ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException (ufe); } return null; } /** Obtain a cookie instance from the copied node in a transferable. * <P> * First of all it checks whether the given transferable contains * a node and then asks for the cookie. * <p>If you wish to specially support multiple-node transfers, please use {@link #nodes} * and manually check for the desired combination of cookies. * * @param t transferable to check in * @param cookie cookie representation class to look for * @param action the action which was used to store the node * * @return cookie or <code>null</code> if it does not exist */ public static Node.Cookie cookie (Transferable t, int action, Class cookie) { Node n = node (t, action); return n == null ? null : n.getCookie (cookie); } /** Creates transfer object that is used to carry an intelligent * paste source through transferable or clipboard. * {@link #findPaste} can retrieve it. * @param paste the intelligent source of paste types * @return the transferable */ public static ExTransferable.Single createPaste (final Paste paste) { return new ExTransferable.Single (nodePasteFlavor) { public Object getData () { return paste; } }; } /** Find an intelligent source of paste types in a transferable. * Note that {@link AbstractNode#createPasteTypes} looks for this * by default, so cut/copied nodes may specify how they may be pasted * to some external node target. * @param t the transferable to test * @return the intelligent source or <code>null</code> if none is in the transferable */ public static Paste findPaste (Transferable t) { try { if (t.isDataFlavorSupported (nodePasteFlavor)) { return (Paste)t.getTransferData (nodePasteFlavor); } } catch (ClassCastException cce) { maybeReportException (cce); } catch (IOException ioe) { maybeReportException (ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException (ufe); } return null; } /** Print a stack trace if debugging is on. * Used for exceptions that could occur when probing transferables, * which should not interrupt the probing with an error, but * indicate a bug elsewhere and should be reported somehow. * @param e the exception */ private static void maybeReportException (Exception e) { if (Boolean.getBoolean ("netbeans.debug.exceptions")) // NOI18N e.printStackTrace (); // else do nothing } /** An intelligent source of paste types (ways how to paste) * for a target node. * <P> * Each node should check for this * type in a paste operation to allow anyone to insert something * into it. * <P> * Sample example of implementation of {@link Node#getPasteTypes}: * <p><code><PRE> * public PasteType[] getPasteTypes (Transferable t) { * NodeTransfer.Paste p = (NodeTransfer.Paste)t.getTransferData ( * NodeTransfer.nodePasteFlavor * ); * return p.types (this); * } * </PRE></code> */ public interface Paste { /** Method that checks the type of target node and can * decide which paste types it supports. * * @param target the target node * @return array of paste types that are valid for such a target node */ public PasteType[] types (Node target); } } /* * Log * 10 Gandalf 1.9 1/12/00 Jesse Glick Removing MIME types from * bundles. * 9 Gandalf 1.8 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 8 Gandalf 1.7 9/21/99 Jesse Glick Added NodeTransger.nodes * to make it easy to handle multiple-selection transfers explicitly. * FolderNode now permits labelled pastes of multiple objects for move, * copy, link, and instantiate. * 7 Gandalf 1.6 7/3/99 Ian Formanek Survives when * Transferable.getTransferDataFlavors returns null * 6 Gandalf 1.5 6/30/99 Jaroslav Tulach Drag and drop support * 5 Gandalf 1.4 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 4 Gandalf 1.3 5/5/99 Jaroslav Tulach Works with 122 * 3 Gandalf 1.2 4/21/99 David Simonek Flavors modified to * correctly support DnD * 2 Gandalf 1.1 3/17/99 Jesse Glick [JavaDoc] * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ */